package top.zhangjianyong.tools.service.api.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import top.zhangjianyong.tools.entity.stock.StockGoods;
import top.zhangjianyong.tools.entity.stock.StockUser;
import top.zhangjianyong.tools.entity.stock.StockUserGoods;
import top.zhangjianyong.tools.mapper.StockUserGoodsMapper;
import top.zhangjianyong.tools.model.stock.StockGoodsVO;
import top.zhangjianyong.tools.parm.stock.StockUserGoodsBorrowListParam;
import top.zhangjianyong.tools.parm.stock.StockUserGoodsBorrowParam;
import top.zhangjianyong.tools.service.api.StockGoodsService;
import top.zhangjianyong.tools.service.api.StockUserGoodsService;
import top.zhangjianyong.tools.user.UserHolder;
import top.zhangjianyong.tools.utils.ApiResponse;
import top.zhangjianyong.tools.utils.LockUtil;

import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * @author zhangjianyong
 * @since 2025/4/1 下午4:39
 */
@Slf4j
@Service
public class StockUserGoodsServiceImpl
        extends ServiceImpl<StockUserGoodsMapper, StockUserGoods> implements StockUserGoodsService {

    private final StockGoodsService stockGoodsService;
    private final StockUserGoodsService stockUserGoodsService;

    public StockUserGoodsServiceImpl(@Lazy StockGoodsService stockGoodsService,
                                     @Lazy StockUserGoodsService stockUserGoodsService) {
        this.stockGoodsService = stockGoodsService;
        this.stockUserGoodsService = stockUserGoodsService;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public ApiResponse borrowReturn(StockUserGoodsBorrowParam param) {
        return LockUtil.excecute(LockUtil.LockKey.STOCK_GOODS.getLockKey(param.getStockGoods()), () -> {
            if (0 == param.getType()) {
                return returnGoods(param);
            } else {
                return borrowGoods(param);
            }
        });

    }

    private ApiResponse borrowGoods(StockUserGoodsBorrowParam param) {
        //已用
        List<StockUserGoods> list = lambdaQuery().eq(StockUserGoods::getStockGoods, param.getStockGoods())
                .gt(StockUserGoods::getUseNum, 0)
                .list();
        int used = list.stream().mapToInt(StockUserGoods::getUseNum).sum();
        StockGoods goods = stockGoodsService.getById(param.getStockGoods());
        if (goods.getTotal() - used < param.getNum()) {
            return ApiResponse.fail("库存不足");
        }
        //查询借还记录没有创建一个
        StockUserGoods one = lambdaQuery()
                .eq(StockUserGoods::getStockGoods, param.getStockGoods())
                .eq(StockUserGoods::getStockUser, UserHolder.userId(StockUser.class))
                .one();
        if (one == null) {
            one = new StockUserGoods();
            one.setStockGoods(param.getStockGoods());
            one.setStockUser(UserHolder.userId(StockUser.class));
            one.setUseNum(0);
            one.setDelFlag(0);
        }

        one.setUseNum(one.getUseNum() + param.getNum());

        return stockUserGoodsService.saveOrUpdate(one) ? ApiResponse.success() : ApiResponse.fail("借还失败");
    }

    private ApiResponse returnGoods(StockUserGoodsBorrowParam param) {
        //查出借出记录
        StockUserGoods one = lambdaQuery()
                .eq(StockUserGoods::getStockGoods, param.getStockGoods())
                .eq(StockUserGoods::getStockUser, UserHolder.userId(StockUser.class))
                .one();
        if (null == one || 0 == one.getUseNum()) {
            return ApiResponse.fail("没有借出");
        }
        if (one.getUseNum() < param.getNum()) {
            return ApiResponse.fail("归还数量超过借出");
        }
        int useNum = one.getUseNum() - param.getNum();
        return lambdaUpdate()
                .eq(StockUserGoods::getId, one.getId())
                .set(StockUserGoods::getUseNum, useNum)
                .update() ? ApiResponse.success() : ApiResponse.fail("更新失败");
    }

    @Override
    public Integer countUsedByGoodsId(Long goodsId) {
        return lambdaQuery()
                .eq(StockUserGoods::getStockGoods, goodsId)
                .list()
                .stream()
                .map(StockUserGoods::getUseNum)
                .mapToInt(Integer::intValue)
                .sum();
    }

    @Override
    public Integer countUsedByGoodsIdAndUserId(Long goodsId, Long userId) {
        return Optional.ofNullable(lambdaQuery()
                        .eq(StockUserGoods::getStockGoods, goodsId)
                        .eq(StockUserGoods::getStockUser, userId)
                        .one())
                .map(StockUserGoods::getUseNum)
                .orElse(0);
    }

    @Override
    public ApiResponse borrowList(StockUserGoodsBorrowListParam param) {
        List<StockGoodsVO> list = stockGoodsService
                .lambdaQuery()
                .eq(StockGoods::getDelFlag, 0)
                .orderByAsc(StockGoods::getName)
                .list().stream().map(stockGoods -> {
                    StockGoodsVO stockGoodsVO = new StockGoodsVO();
                    BeanUtils.copyProperties(stockGoods, stockGoodsVO);
                    return stockGoodsVO;
                }).collect(Collectors.toList());
        for (StockGoodsVO stockGoodsVO : list) {
            Integer used = stockUserGoodsService.countUsedByGoodsId(stockGoodsVO.getId());
            stockGoodsVO.setUsed(used);
            Integer currentUsed = stockUserGoodsService
                    .countUsedByGoodsIdAndUserId(stockGoodsVO.getId(), UserHolder.userId(StockUser.class));
            stockGoodsVO.setCurrentUsed(currentUsed);
        }
        return ApiResponse.success(list);
    }
}
